<template>
    <div class="cs-leaderboard-wrapper" v-draggable-resizable="{
        initialPosition: { x: 50, y: 50 },
        minWidth: 800, minHeight: 600,
        initialWidth: 840, initialHeight: 560,
        initialVisible: false,
        controlPosition: 'top-right',
        hideHintText: 'CS排行榜'
    }" ref="csLeaderboardRef">

        <!-- 加载遮罩 -->
        <div class="loading-overlay"
            v-show="(!videInfo[0].isLoadSuccess || !videInfo[1].isLoadSuccess || isLoading) && shouldShowContent">
            <div class="loading-content">
                <div class="loading-spinner"></div>
                <div class="loading-text">{{ loadingText }}</div>
            </div>
        </div>

        <!-- 视频容器 -->
        <div class="video-container" v-show="shouldShowContent">
            <!-- 预加载两个视频到内存 -->
            <video ref="redVideoRef" :src="redVideoSrc" muted class="fullscreen-video" preload="auto"
                style="display: none;" />
            <video ref="blueVideoRef" :src="blueVideoSrc" muted class="fullscreen-video" preload="auto"
                style="display: none;" />
            <!-- 当前播放的视频 -->
            <video ref="currentVideoRef" muted class="fullscreen-video" preload="auto" />

            <!-- 玩家卡片 - 前4名 -->
            <div v-for="(player, index) in filteredTop4Players" v-if="cardsVisible" :key="player.player_id || index"
                class="player-card" :style="{
                    left: `${cardPositions[index].x}%`,
                    top: `${cardPositions[index].y}%`,
                    transform: `scale(${cardScales[index]})`,
                    opacity: cardOpacities[index],
                    transition: `all ${animationDuration}s linear`
                }">
                <div class="player-rank">
                    <img v-if="getRankImage(index + 1)" :src="getRankImage(index + 1)" :alt="`第${index + 1}名`"
                        class="rank-image">
                    <span v-else class="rank-number">{{ index + 1 }}</span>
                </div>
                <div class="player-info">
                    <div class="player-name">{{ player.player_name }}</div>
                    <div class="player-score">
                        <span v-if="currentDisplayMode === 'season'">积分: {{ animatedScores[index] }}</span>
                        <span v-else>分数: {{ animatedScores[index] }}</span>
                    </div>
                </div>
            </div>

            <!-- 排行榜容器 -->
            <div class="leaderboard-container"
                v-if="(filteredPlayersForLeaderboard.length > 0 || currentDisplayMode === 'settlement') && isLeaderboardContainerVisible"
                @mouseenter="isScrollingPaused = true" @mouseleave="isScrollingPaused = false">
                <div class="leaderboard-header">
                    <span v-if="currentDisplayMode === 'season'">S{{ currentSeasonNumber || props.season }}
                        排行榜</span>
                    <span v-else-if="currentDisplayMode === 'game'">
                        本局排行榜
                        <span v-if="currentDisplayTeam === 'red'"> - 🔴红队</span>
                        <span v-else-if="currentDisplayTeam === 'blue'"> - 🔵蓝队</span>
                    </span>
                    <span v-else-if="currentDisplayMode === 'settlement'">
                        <span v-if="currentDisplayTeam === 'red'">🔴 {{ props.winTeam === 'red' ? '红队胜利' : '红队失败'
                            }}</span>
                        <span v-else-if="currentDisplayTeam === 'blue'">🔵 {{ props.winTeam === 'blue' ? '蓝队胜利' :
                            '蓝队失败' }}</span>
                        <span v-else>{{ props.winTeam === 'red' ? '🔴 红队胜利' : '🔵 蓝队胜利' }}</span>
                    </span>
                </div>
                <div class="leaderboard-content" ref="leaderboardContentRef">
                    <div v-for="(player, index) in filteredPlayersForLeaderboard" :key="player.player_id || index"
                        class="player-row">
                        <div class="rank">
                            <img v-if="getRankImage(index + 5)" :src="getRankImage(index + 5)" :alt="`第${index + 5}名`"
                                class="rank-list-image">
                            <span v-else class="rank-number">{{ index + 5 }}</span>
                        </div>
                        <div class="player-name">{{ player.player_name }}</div>
                        <div class="score">
                            <span v-if="currentDisplayMode === 'season'">{{ (player as any).points || 0 }}</span>
                            <span v-else-if="currentDisplayMode === 'settlement'">{{ (player as any).finalScore || 0
                            }}</span>
                            <span v-else>{{ player.score || player.sortValue || 0 }}</span>
                        </div>
                    </div>
                </div>
            </div>

            <!-- 空状态显示 -->
            <div v-if="allPlayers.length === 0 && isContentVisible" class="empty-state">
                <div class="empty-icon">📊</div>
                <div class="empty-text">
                    <span v-if="currentDisplayMode === 'season'">暂无赛季排行榜数据</span>
                    <span v-else-if="currentDisplayMode === 'game'">暂无本局排行榜数据</span>
                    <span v-else-if="currentDisplayMode === 'settlement'">暂无结算数据</span>
                    <span v-else>暂无排行榜数据</span>
                </div>
            </div>
        </div>
    </div>
</template>

<script setup lang="ts">
import { defineOptions } from 'vue'
import { ref, onMounted, computed, reactive, onUnmounted, nextTick, watch } from 'vue';
import eventBus from 'vue3-eventbus';
import getApi from '@/api/modules/get';
import postApi from '@/api/modules/post';
import { initSettlementScreen, videInfo } from '@/utils/indexedDB';
import type { Props } from '@/assets/common/types/Leaderboard'
import { calculatePlayerScores } from '@/utils/scoreCalculator'

// ================================================================================================
// Component Props and Emits - 组件属性与事件
// ================================================================================================
defineOptions({ name: 'CSLeaderboard' })

/**
 * @description 获取CS排行榜相关图片资源的路径
 * @param {string} imageName - 图片文件名
 * @returns {string} - 图片的完整URL
 */
function getCSImageUrl(imageName: string) {
    return new URL(`../../assets/cs/leaderboard/${imageName}`, import.meta.url).href
}

/**
 * @description 根据排名获取对应的奖牌图片，1-4名有特定图片
 * @param {number} rank - 玩家排名
 * @returns {string} - 奖牌图片的URL，如果无特定图片则返回空字符串
 */
function getRankImage(rank: number) {
    if (rank >= 1 && rank <= 4) {
        return getCSImageUrl(`${rank}.png`)
    }
    return ''
}

// Props定义
const props = withDefaults(defineProps<Omit<Props, 'leaderboardType'>>(), {
    leftPlayer: () => [],
    rightPlayer: () => [],
    messages: () => [],
    pointPool: 0,
    winTeam: '',
    visible: false,
    gameId: 6,
    season: undefined,
})

// Emits定义
const emit = defineEmits<{
    'display-completed': [playerResults: any[]]
}>()

// ================================================================================================
// Refs and Reactive States - 响应式状态和引用
// ================================================================================================

// 视频元素引用
const redVideoRef = ref<HTMLVideoElement>()
const blueVideoRef = ref<HTMLVideoElement>()
const currentVideoRef = ref<HTMLVideoElement>()
const csLeaderboardRef = ref<HTMLElement>() // 对组件根元素的引用

// 视频源（预加载到内存中）
const redVideoSrc = ref("")
const blueVideoSrc = ref("")

// ================================================================================================
// Video Load State - 判断两段视频是否均已加载完成
// ================================================================================================

const bothVideosLoaded = computed(() => videInfo.value[0].isLoadSuccess && videInfo.value[1].isLoadSuccess)

// 基础状态
const isLoading = ref(false)                // 通用加载状态
const seasonLeaderboardData = ref([])       // 赛季排行榜数据
const currentSeasonNumber = ref(null)       // 当前赛季编号
const isSeasonDataLoading = ref(false)      // 赛季数据是否正在加载
const isDirectiveVisible = ref(true)                                            // v-draggable-resizable指令的可见性状态
const isLeaderboardContainerVisible = ref(false)                                // 排行榜容器（第5名及以后）的可见性
const currentDisplayTeam = ref<'red' | 'blue' | 'all'>('all')                   // 当前显示的队伍
const currentDisplayMode = ref<'game' | 'season' | 'settlement' | 'none'>('none'); // 新增：内部显示模式

// 动画配置
const animationDuration = 2 // 动画持续时间（秒）
const initialScale = 0.1    // 初始缩放比例
const CARD_POSITIONS = [
    { x: 41.7, y: 20 },  // 第1名
    { x: 10, y: 20 },    // 第2名
    { x: 60, y: 30 },    // 第3名
    { x: 80, y: 35 }     // 第4名
]

// 动画状态
const cardPositions = reactive([...CARD_POSITIONS])                                     // 卡片位置
const cardScales = reactive([initialScale, initialScale, initialScale, initialScale])   // 卡片缩放
const cardOpacities = reactive([0, 0, 0, 0])                                            // 卡片不透明度
const animatedScores = reactive<number[]>(new Array(10).fill(0))                        // 动态变化的积分数字

// 控制卡片是否渲染，用于立即卸载并重建以重置动画
const cardsVisible = ref(true)
const leaderboardContentRef = ref<HTMLElement | null>(null);                            // 排行榜滚动区域的引用
const scrollInterval = ref<number | null>(null);                                        // 自动滚动定时器
const isScrollingPaused = ref(false);                                                   // 用户是否暂停了滚动
const scrollCompletedCallback = ref<(() => void) | null>(null);                         // 滚动完成后的回调

// ================================================================================================
// Watchers - 监听器
// ================================================================================================

// 当队伍切换时，重置排行榜滚动条位置，确保每个队伍从列表顶部开始
watch(currentDisplayTeam, (newTeam, oldTeam) => {
    // 仅在“本局”或“结算”模式下才需要根据队伍切换重新滚动；赛季模式保持一次完整滚动
    if ((currentDisplayMode.value === 'game' || currentDisplayMode.value === 'settlement') &&
        newTeam !== oldTeam && newTeam !== 'all') {
        nextTick(() => {
            if (leaderboardContentRef.value) {
                // 先立即重置到顶部
                leaderboardContentRef.value.scrollTop = 0
            }

            // 重新启动自动滚动，保证下一个队伍仍会滚动
            stopAutoScroll()
            startAutoScroll()
        })
    }
})

// ================================================================================================
// Session Guard - 会话标识，防止上一模式的延迟回调干扰当前模式
// ================================================================================================
const sessionIdCounter = ref(0)

const safeSetTimeout = (fn: () => void, delay: number, sessionId: number) => {
    const timer = setTimeout(() => {
        if (sessionIdCounter.value !== sessionId) return // 会话已变，忽略旧回调
        fn()
    }, delay)
    activeAnimationTimers.value.push(timer as unknown as number)
    return timer
}

// ================================================================================================
// Computed Properties - 计算属性
// ================================================================================================

/**
 * @description 根据视频加载状态动态生成加载提示文本
 */
const loadingText = computed(() => {
    if (!videInfo.value[0].isLoadSuccess || !videInfo.value[1].isLoadSuccess) {
        return `${videInfo.value[0].txt}\n${videInfo.value[1].txt}\nPS: 只需下载一次，下载过程中退出网页将重新下载，结算画面最终将保存在浏览器中`;
    }
    return '加载中...';
})

/**
 * @description 停止排行榜的自动滚动
 */
const stopAutoScroll = () => {
    // 若有正在计时的滚动，立即终止
    if (scrollInterval.value) {
        clearInterval(scrollInterval.value)
        scrollInterval.value = null
    }

    // 若存在尚未 resolve 的 Promise，主动触发回调，防止外部 await 永久挂起
    if (scrollCompletedCallback.value) {
        try {
            scrollCompletedCallback.value()
        } finally {
            scrollCompletedCallback.value = null
        }
    }
};

/**
 * @description 启动排行榜的自动滚动，并在滚动结束后resolve一个Promise
 * @returns {Promise<void>}
 */
const startAutoScroll = () => {
    console.log('🎯 开始自动滚动...')
    stopAutoScroll();
    return new Promise<void>((resolve) => {
        scrollCompletedCallback.value = resolve;

        nextTick(() => {
            const el = leaderboardContentRef.value;
            if (!el) {
                console.log('❌ 滚动元素不存在')
                resolve();
                return;
            }

            // 等待DOM渲染完成
            nextTick(() => {
                const { scrollHeight, clientHeight } = el;
                console.log('📐 滚动尺寸:', { scrollHeight, clientHeight, needScroll: scrollHeight > clientHeight });

                if (scrollHeight <= clientHeight) {
                    console.log('✅ 内容不需要滚动，立即完成')
                    resolve();
                    return;
                }

                let hasScrolledToBottom = false;
                let scrollAttempts = 0;
                const maxScrollAttempts = 10; // 最大滚动次数保护

                scrollInterval.value = setInterval(() => {
                    if (isScrollingPaused.value || hasScrolledToBottom) return;

                    scrollAttempts++;
                    const { scrollTop, scrollHeight: currentScrollHeight, clientHeight: currentClientHeight } = el;

                    console.log(`📜 滚动尝试 ${scrollAttempts}:`, {
                        scrollTop,
                        scrollHeight: currentScrollHeight,
                        clientHeight: currentClientHeight,
                        remaining: currentScrollHeight - scrollTop - currentClientHeight
                    });

                    // 检查是否已经到达底部（使用更宽松的条件）
                    const isAtBottom = scrollTop >= currentScrollHeight - currentClientHeight - 5;

                    if (isAtBottom || scrollAttempts >= maxScrollAttempts) {
                        console.log('🎯 滚动完成！', {
                            reason: isAtBottom ? '到达底部' : '达到最大尝试次数',
                            scrollTop,
                            scrollHeight: currentScrollHeight,
                            clientHeight: currentClientHeight
                        });
                        hasScrolledToBottom = true;
                        stopAutoScroll();
                        resolve();
                    } else {
                        // 向下滚动一页
                        const newScrollTop = scrollTop + currentClientHeight;
                        console.log(`⬇️ 滚动到: ${newScrollTop}`);
                        el.scrollTo({ top: newScrollTop, behavior: 'smooth' });
                    }
                }, 2000);
            }); // 给DOM一点时间渲染
        });
    });
};

/**
 * @description 从IndexedDB预加载视频数据到内存中，以便快速播放
 */
const preloadVideos = async () => {
    console.log('🎬 开始预加载视频到内存...');

    if (videInfo.value[0]?.isLoadSuccess && videInfo.value[0]?.indexDB_URL) {
        redVideoSrc.value = videInfo.value[0].indexDB_URL;
        console.log('🔴 红队视频预加载完成');
    }

    if (videInfo.value[1]?.isLoadSuccess && videInfo.value[1]?.indexDB_URL) {
        blueVideoSrc.value = videInfo.value[1].indexDB_URL;
        console.log('🔵 蓝队视频预加载完成');
    }
}

/**
 * @description 从API异步获取赛季排行榜数据
 */
const fetchSeasonLeaderboard = async () => {
    isSeasonDataLoading.value = true;
    try {
        const params: any = { game_id: props.gameId, limit: 20 };
        if (props.season) params.season = props.season;

        const response = await getApi.getSeasonLeaderboard(params);
        if (response?.data) {
            seasonLeaderboardData.value = response.data.data || [];
            currentSeasonNumber.value = response.data.current_season;
        }
    } catch (error) {
        seasonLeaderboardData.value = [];
        currentSeasonNumber.value = null;
    } finally {
        isSeasonDataLoading.value = false;
    }
};

/**
 * @description 调用通用工具函数计算所有玩家的最终得分
 * @returns {Array} - 带有最终得分的玩家数组
 */
const calculateFinalScores = () => {
    return calculatePlayerScores(
        [...props.leftPlayer, ...props.rightPlayer],
        props.messages,
        props.winTeam,
        props.pointPool,
        'CS'
    );
}

/**
 * @description 生成用于提交到后端的玩家结算数据结构
 * @returns {Array} - 符合后端接口要求的玩家结算数据数组
 */
const generatePlayerResults = () => {
    const playersWithFinalScores = calculateFinalScores()
    return playersWithFinalScores.map(player => {
        const playerMessages = props.messages.filter(msg => msg.player_id === player.player_id)
        const baseMessage = playerMessages[0] || {}
        return {
            uuid: (baseMessage as any).uuid || '',
            game_id: (baseMessage as any).game_id || 6,
            userid_platform: (baseMessage as any).userid_platform || player.userid_platform || '',
            player_name: player.player_name,
            point: (player as any).finalScore || 0,
            team: player.team,
            units: player.units || 0,
            is_winner: (player.team === props.winTeam),
            is_test: (baseMessage as any).anchor_id == '111admin' || (baseMessage as any).anchor_id == '222admin',          // 是否测试
        }
    }).filter(result => result.point > 0 || (props.pointPool === 0 && props.winTeam))
}

// 数据过滤计算属性

/**
 * @description 根据当前显示的队伍，过滤出排名前4的玩家用于卡片展示
 */
const filteredTop4Players = computed(() => {
    if (currentDisplayMode.value === 'season') {
        return allPlayers.value.slice(0, 4)
    }
    if (currentDisplayTeam.value === 'all') {
        return allPlayers.value.slice(0, 4)
    }
    return allPlayers.value.filter(player => player.team === currentDisplayTeam.value).slice(0, 4)
})

/**
 * @description 根据当前显示的队伍，过滤出第5名及以后的玩家用于列表展示
 */
const filteredPlayersForLeaderboard = computed(() => {
    if (currentDisplayMode.value === 'season') {
        return allPlayers.value.slice(4)
    }
    if (currentDisplayTeam.value === 'all') {
        return allPlayers.value.slice(4)
    }
    return allPlayers.value.filter(player => player.team === currentDisplayTeam.value).slice(4)
})

/**
 * @description 根据排行榜类型，合并、排序并返回所有玩家的数据源
 */
const allPlayers = computed(() => {
    switch (currentDisplayMode.value) {
        case 'season':
            return seasonLeaderboardData.value.sort((a: any, b: any) => a.rank - b.rank);
        case 'game':
            const allGamePlayers = [...props.leftPlayer, ...props.rightPlayer];
            return allGamePlayers.sort((a, b) => (b.score || b.sortValue || 0) - (a.score || a.sortValue || 0));
        case 'settlement':
            if (!props.winTeam || props.messages.length === 0) return [];
            const playersWithFinalScores = calculateFinalScores();
            return playersWithFinalScores.sort((a, b) => (b as any).finalScore - (a as any).finalScore);
        default:
            return [];
    }
})

// ================================================================================================
// UI and Visibility State - UI与可见性状态
// ================================================================================================

/**
 * @description 更新v-draggable-resizable指令的内部可见性状态
 */
const updateDirectiveVisibility = () => {
    const el = csLeaderboardRef.value as any
    if (el?._draggableResizable) {
        isDirectiveVisible.value = el._draggableResizable.state.isVisible
    }
}

/**
 * @description 控制UI是否应该被渲染（初始状态或v-draggable-resizable的外部控制）
 */
const shouldShowContent = computed(() => props.visible && isDirectiveVisible.value)

/**
 * @description 控制UI内容是否可见，用于实现淡入淡出效果
 */
const isContentVisible = ref(false)

/**
 * @description 当前活动的动画计时器ID
 */
const activeAnimationTimers = ref<number[]>([])

/**
 * @description 创建一个从start到end的数字缓动动画
 * @param {number} startValue - 起始值
 * @param {number} endValue - 结束值
 * @param {number} duration - 持续时间（毫秒）
 * @param {Function} callback - 每帧更新时的回调函数
 */
const animateNumber = (startValue: number, endValue: number, duration: number, callback: (value: number) => void) => {
    const startTime = Date.now()
    const animate = () => {
        const elapsed = Date.now() - startTime
        const progress = Math.min(elapsed / duration, 1)
        const easeOutQuart = 1 - Math.pow(1 - progress, 4)
        const currentValue = Math.floor(startValue + (endValue - startValue) * easeOutQuart)
        callback(currentValue)
        if (progress < 1) requestAnimationFrame(animate)
    }
    requestAnimationFrame(animate)
}

/**
 * @description 启动所有UI动画（卡片、数字等）的入口函数
 */
const startAnimations = () => {
    startAnimationsCore(false);
}

/**
 * @description 专门为赛季排行榜设计，启动动画并等待滚动完成
 * @returns {Promise<void>}
 */
const startAnimationsAndWaitScroll = async () => {
    return await startAnimationsCore(true);
}

/**
 * @description 核心动画逻辑，负责启动数字和卡片动画，并可选地等待滚动完成
 * @param {boolean} waitForScroll - 是否需要等待列表滚动完成
 * @returns {Promise<void> | undefined}
 */
const startAnimationsCore = (waitForScroll: boolean) => {
    // 数字动画
    const players = allPlayers.value.slice(0, 10)
    players.forEach((player, i) => {
        setTimeout(() => {
            let finalScore = 0
            if (currentDisplayMode.value === 'season') {
                finalScore = (player as any).points || 0
            } else if (currentDisplayMode.value === 'game') {
                finalScore = player.score !== undefined ? player.score : (player.sortValue || 0)
            } else if (currentDisplayMode.value === 'settlement' && 'finalScore' in player) {
                finalScore = (player as any).finalScore
            } else if (props.winTeam && props.messages.length > 0 && 'finalScore' in player) {
                finalScore = (player as any).finalScore
            } else {
                finalScore = player.score !== undefined ? player.score : (player.sortValue || 0)
            }
            const clampedScore = Math.max(0, finalScore)
            animateNumber(0, clampedScore, 1500, (value) => {
                animatedScores[i] = value
            })
        }, i * 100 + 1000)
    })

    // 卡片动画
    isLeaderboardContainerVisible.value = true
    const scrollPromise = startAutoScroll();
    filteredTop4Players.value.forEach((_, index) => {
        setTimeout(() => {
            cardPositions[index] = CARD_POSITIONS[index]
            cardScales[index] = 1
            cardOpacities[index] = 1
        }, 200 + index * 200)
    })

    return waitForScroll ? scrollPromise : undefined;
}

/**
 * @description 核心显示逻辑，设置可见性并允许空状态显示
 */
const handleShowContent = () => {
    isContentVisible.value = true
}

/**
 * @description 重置所有动画相关的状态到初始值
 */
const resetAnimations = () => {
    for (let i = 0; i < 10; i++) {
        animatedScores[i] = 0
    }
    cardScales.forEach((_, index) => {
        cardScales[index] = initialScale
        cardOpacities[index] = 0
    })
    CARD_POSITIONS.forEach((pos, index) => {
        cardPositions[index] = { ...pos }
    })
    isLeaderboardContainerVisible.value = false
    stopAutoScroll();
    // 切换队伍重新展示排行榜时，将滚动条位置重置到顶部，避免继续沿用上一次的位置
    if (leaderboardContentRef.value) {
        leaderboardContentRef.value.scrollTop = 0;
    }
    currentDisplayTeam.value = 'all'
}

/**
 * @description 立即卸载并重新渲染卡片，以实现动画快速重置
 */
const instantCardReset = async () => {
    cardsVisible.value = false
    await nextTick()
    resetAnimations()
    cardsVisible.value = true
    await nextTick()
    startAnimations()
}

/**
 * @description 播放隐藏动画，将卡片等元素移出视野
 */
const hideAnimations = () => {
    isLeaderboardContainerVisible.value = false
    stopAutoScroll();
    for (let index = 0; index < 4; index++) {
        const timerId = setTimeout(() => {
            cardScales[index] = initialScale
            cardOpacities[index] = 0
            cardPositions[index] = { x: 0, y: 0 }
            if (index === 3) {
                setTimeout(() => {
                    currentDisplayTeam.value = 'all'
                }, 200)
            }
        }, index * 80)
        activeAnimationTimers.value.push(timerId as unknown as number)
    }
}

/**
 * @description 在调用 hideAnimations 前检查会话是否仍然有效，防止旧动画影响新模式
 * @param {number} id - 调用时所在的会话ID
 */
const safeHideAnimations = (id: number) => {
    if (sessionIdCounter.value !== id) return;

    hideAnimations();

    // 在隐藏动画启动后，稍微延迟清空当前视频源，避免黑屏闪烁
    safeSetTimeout(() => {
        if (currentVideoRef.value) {
            currentVideoRef.value.pause();
            currentVideoRef.value.src = '';
            currentVideoRef.value.load();
        }

        // 向父组件发送完成事件（如果需要）
        emit('display-completed', []);
    }, 300, id);
}

/**
 * @description 播放指定队伍的视频，并处理播放过程中的各种情况
 * @param {HTMLVideoElement} videoElement - 包含视频源的video元素
 * @param {string} teamName - 队伍名称（'红队'或'蓝队'）
 * @returns {Promise<boolean>} - 视频是否成功播放完毕
 */
const playVideo = (videoElement: HTMLVideoElement, teamName: string, callSessionId: number = sessionIdCounter.value) => {
    return new Promise<boolean>((resolve) => {
        const videoToPlay = currentVideoRef.value;
        if (!videoElement?.src || !videoToPlay) {
            resolve(false);
            return;
        }

        let hasEnded = false;

        const cleanup = () => {
            videoToPlay.ontimeupdate = null;
            videoToPlay.onended = null;
            videoToPlay.onerror = null;
        };

        const onEnded = () => {
            // 会话已切换，忽略旧事件
            if (sessionIdCounter.value !== callSessionId) {
                cleanup();
                return;
            }
            if (!hasEnded) {
                hasEnded = true;
                cleanup();
                resolve(true);
            }
        };

        const onTimeUpdate = () => {
            if (sessionIdCounter.value !== callSessionId) return;
            // 赛季排行榜模式：提前1秒暂停而不是结束
            if (currentDisplayMode.value === 'season' && !hasEnded && videoToPlay.duration && videoToPlay.currentTime >= videoToPlay.duration - 1) {
                console.log('⏸️ 赛季排行榜视频播放到最后1秒，暂停视频')
                videoToPlay.pause();
                hasEnded = true;
                cleanup();
                resolve(true);
            }
            // 其他模式：提前1秒结束
            else if (currentDisplayMode.value !== 'season' && !hasEnded && videoToPlay.duration && videoToPlay.currentTime >= videoToPlay.duration - 1) {
                hasEnded = true;
                cleanup();
                resolve(true);
            }
        };

        const onError = () => {
            if (sessionIdCounter.value !== callSessionId) {
                cleanup();
                return;
            }
            cleanup();
            resolve(false);
        };

        // Assign event listeners
        videoToPlay.onended = onEnded;
        videoToPlay.ontimeupdate = onTimeUpdate;
        videoToPlay.onerror = onError;

        // Set src and play
        videoToPlay.src = videoElement.src;
        videoToPlay.load();
        videoToPlay.play().then(() => {
            if (sessionIdCounter.value !== callSessionId) return;
            currentDisplayTeam.value = teamName === '红队' ? 'red' : 'blue';
            console.log(`▶️ 开始播放${teamName}视频 (${currentDisplayMode.value}模式)`);
        }).catch((e) => {
            if (sessionIdCounter.value !== callSessionId) {
                cleanup();
                return; // ignore
            }
            console.error("Video play failed:", e);
            cleanup();
            resolve(false);
        });

        // Timeout protection
        setTimeout(() => {
            if (sessionIdCounter.value !== callSessionId) {
                cleanup();
                return;
            }
            if (!hasEnded) {
                cleanup();
                resolve(false);
            }
        }, 10000);
    });
};


/**
 * 停止所有正在进行的动画计时器。
 */
const stopAllAnimations = () => {
    activeAnimationTimers.value.forEach(timerId => clearTimeout(timerId))
    activeAnimationTimers.value = []
}

/**
 * 停止所有视频的播放并重置它们的状态。
 */
const stopAllVideos = () => {
    // 预加载的红蓝队视频只需要暂停并归零, 不要清空 src, 以便后续直接播放
    [redVideoRef.value, blueVideoRef.value].forEach(player => {
        if (player) {
            player.pause()
            player.currentTime = 0
        }
    })

    // 当前播放的视频只暂停并归零，不立即清空 src，避免在模式切换瞬间出现黑屏闪烁
    if (currentVideoRef.value) {
        currentVideoRef.value.pause()
        currentVideoRef.value.currentTime = 0
        // currentVideoRef.value.src = ''   // 延迟到真正隐藏时再清空
        // currentVideoRef.value.load()
    }
}

/**
 * @description 清理之前模式的所有动画、视频和定时器，防止延迟定时器影响下一模式
 */
const cleanupPreviousDisplay = () => {
    stopAutoScroll();         // 停止排行榜滚动
    // 不再调用 hideAnimations，以免在切换模式时卡牌提前收起
    stopAllAnimations();      // 清除所有计时器（包括此前 hideAnimations 推入的计时器）
    resetAnimations();        // 立即将卡片/数字状态复位，确保下次从初始开始
    stopAllVideos();          // 停止并重置视频
    if (currentVideoRef.value) {
        currentVideoRef.value.src = '';
        currentVideoRef.value.load();
    }
}

// Vue生命周期钩子
onMounted(() => {
    // 初始化IndexedDB
    initSettlementScreen()
    // 预加载视频资源
    preloadVideos()

    // 定时检查指令的可见性状态
    const checkDirectiveState = () => updateDirectiveVisibility()
    setTimeout(checkDirectiveState, 100)
    const stateChecker = setInterval(checkDirectiveState, 200)

    // 组件卸载时清理定时器
    onUnmounted(() => {
        clearInterval(stateChecker);
        stopAutoScroll();
    })

    // 监听通过eventBus派发的全局Socket消息
    eventBus.on('socket-message', message => {
        const { type, scope } = message;

        switch (type) {
            case 'leaderboard':
                // 若视频尚未全部加载完成，只显示加载界面，忽略排行榜请求
                if (!bothVideosLoaded.value) {
                    return;
                }
                // 在开始处理新模式之前，先彻底清理上一模式留下的定时器和视频，防止串扰
                cleanupPreviousDisplay();
                const sessionId = ++sessionIdCounter.value; // 当前会话ID

                if (scope === 'season' || scope === 'game') {
                    console.log(`📊 收到排行榜消息: ${scope}`);
                    currentDisplayMode.value = scope;
                    preloadVideos(); // 在显示前确保视频已加载

                    if (scope === 'season') {
                        isLoading.value = true;
                        fetchSeasonLeaderboard().then(async () => {
                            isLoading.value = false;
                            handleShowContent();

                            // --- 赛季模式视频控制逻辑 ---
                            if (!currentVideoRef.value) return;
                            const redAvailable = redVideoRef.value && redVideoSrc.value;

                            if (redAvailable) {
                                resetAnimations();
                                const animationsPromise = startAnimationsAndWaitScroll();
                                const videoPromise = playVideo(redVideoRef.value!, '红队');
                                await Promise.all([videoPromise, animationsPromise]);
                                safeHideAnimations(sessionId);
                            } else {
                                currentDisplayTeam.value = 'all';
                                resetAnimations();
                                await startAnimationsAndWaitScroll();
                                safeHideAnimations(sessionId);
                            }
                        });
                    } else { // game
                        handleShowContent();
                        nextTick(async () => {
                            // --- 本局模式视频控制逻辑 ---
                            if (!currentVideoRef.value) return;

                            const redAvailable = redVideoRef.value && redVideoSrc.value;
                            const blueAvailable = blueVideoRef.value && blueVideoSrc.value;

                            const hasRed = allPlayers.value.some(p => p.team === 'red') || props.leftPlayer.some(p => p.team === 'red') || props.rightPlayer.some(p => p.team === 'red');
                            const hasBlue = allPlayers.value.some(p => p.team === 'blue') || props.leftPlayer.some(p => p.team === 'blue') || props.rightPlayer.some(p => p.team === 'blue');

                            const shouldPlayRed = redAvailable && hasRed;
                            const shouldPlayBlue = blueAvailable && hasBlue;

                            resetAnimations();
                            startAnimations();

                            if (shouldPlayRed && shouldPlayBlue) {
                                if (props.winTeam === 'red') {
                                    await playVideo(redVideoRef.value!, '红队');
                                    await instantCardReset();
                                    await playVideo(blueVideoRef.value!, '蓝队');
                                } else {
                                    await playVideo(blueVideoRef.value!, '蓝队');
                                    await instantCardReset();
                                    await playVideo(redVideoRef.value!, '红队');
                                }
                            } else if (shouldPlayRed) {
                                await playVideo(redVideoRef.value!, '红队');
                            } else if (shouldPlayBlue) {
                                await playVideo(blueVideoRef.value!, '蓝队');
                            }

                            safeHideAnimations(sessionId);
                        });
                    }
                }
                break;

            case 'settle':
                // 结算同样依赖视频资源
                if (!bothVideosLoaded.value) {
                    return;
                }
                console.log('🏁 收到结算消息:', message.winTeam);
                // 为结算流程开启新的会话，避免与上一模式的回调混淆
                const settlementSessionId = ++sessionIdCounter.value;
                currentDisplayMode.value = 'settlement';
                preloadVideos(); // 在显示前确保视频已加载

                // --- 原 processPendingSettlement 的逻辑 ---
                console.log('🎮 处理结算数据...');
                nextTick(async () => {
                    const hasBasicData = message.winTeam && (props.leftPlayer.length > 0 || props.rightPlayer.length > 0)
                    if (shouldShowContent.value && hasBasicData) {
                        const playerResults = generatePlayerResults()
                        if (playerResults?.length > 0) {
                            postApi.settleGame(playerResults).then(res => {
                                console.log('✅ 结算数据提交成功:', res)
                            }).catch(err => {
                                console.error('❌ 结算数据提交失败:', err)
                            })
                            try {
                                if (props.pointPool <= 0) return;
                                let res = await postApi.updateAnchorData({
                                    anchor_id: props.anchorId,
                                    game_id: props.gameId,
                                    point_pool: Math.round(props.pointPool / 2)
                                })
                                console.log('积分池更新成功:', res);
                            } catch (error) {
                                console.error('积分池更新失败:', error);
                            }
                        }

                        handleShowContent();
                        nextTick(async () => {
                            resetAnimations();
                            startAnimations();

                            if (!currentVideoRef.value) return;

                            const redAvailable = redVideoRef.value && redVideoSrc.value;
                            const blueAvailable = blueVideoRef.value && blueVideoSrc.value;

                            const hasRed = allPlayers.value.some(p => p.team === 'red') || props.leftPlayer.some(p => p.team === 'red') || props.rightPlayer.some(p => p.team === 'red');
                            const hasBlue = allPlayers.value.some(p => p.team === 'blue') || props.leftPlayer.some(p => p.team === 'blue') || props.rightPlayer.some(p => p.team === 'blue');

                            const shouldPlayRed = redAvailable && hasRed;
                            const shouldPlayBlue = blueAvailable && hasBlue;

                            if (!shouldPlayRed && !shouldPlayBlue) {
                                currentDisplayTeam.value = 'all';
                                startAnimations();
                                setTimeout(() => {
                                    safeHideAnimations(settlementSessionId);
                                }, 3000);
                                return;
                            }

                            if (shouldPlayRed && shouldPlayBlue) {
                                if (props.winTeam === 'red') {
                                    await playVideo(redVideoRef.value!, '红队');
                                    await instantCardReset();
                                    await playVideo(blueVideoRef.value!, '蓝队');
                                } else {
                                    await playVideo(blueVideoRef.value!, '蓝队');
                                    await instantCardReset();
                                    await playVideo(redVideoRef.value!, '红队');
                                }
                            } else if (shouldPlayRed) {
                                await playVideo(redVideoRef.value!, '红队');
                            } else if (shouldPlayBlue) {
                                await playVideo(blueVideoRef.value!, '蓝队');
                            }

                            safeHideAnimations(settlementSessionId);
                        })
                    }
                })
                break;

            case 'closeLeaderboard':
                console.log('🧹 收到关闭排行榜消息');
                // 结束当前会话，防止旧定时器继续执行
                ++sessionIdCounter.value;

                // 立即隐藏内容
                isContentVisible.value = false;

                // 清理所有视频、动画、滚动等
                cleanupPreviousDisplay();

                // 触发完成事件，通知父组件流程结束
                emit('display-completed', []);
                break;
        }
    });
})
</script>

<style scoped lang="less">
@import '@/assets/cs/css/Leaderboard.less';
</style>